﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Configuration;
using System.Linq;
using System.Reflection;

namespace Trade.Journal
{
    public class NewRecordWindowViewModel : BindableBase
    {

        public static ReleaseDirection[] ReleaseDirections { get; } = new ReleaseDirection[] { Journal.ReleaseDirection.Up, Journal.ReleaseDirection.Down };
        public static ReleaseLevel[] ReleaseLevels { get; } = new ReleaseLevel[] { Journal.ReleaseLevel.Explode, Journal.ReleaseLevel.Fast, Journal.ReleaseLevel.Normal, Journal.ReleaseLevel.Channel };


        private Record record = new Record();


        public bool CanOpen
        {
            get { return !string.IsNullOrWhiteSpace(Contract) && CanClose; }
        }


        public bool CanSave
        {
            get { return !string.IsNullOrWhiteSpace(Contract) /*&& Completeness > 50*/; }
        }

        public bool CanClose
        {
            get { return IsAvailable(OpenDeal); }
        }

        public bool IsOpportunityFilled => Opportunity != null && OpportunityCycle != default && ReleaseBarCount.HasValue && ReleaseDirection.HasValue && ReleaseLevel.HasValue && ReleaseScope.HasValue && CumulationBarCount.HasValue && CumulationScope.HasValue;


        public string RecordId => record.Id;

        public string Contract
        {
            get { return record.Contract; }
            set { record.Contract = value; NotifyPropertyChanged(); Multiplicator = DbHelper.QueryMultiplicator(value); NotifyPropertyChanged(nameof(CanOpen)); }
        }

        public ObservableCollection<Relationship> RelativeTrades { get; } = new ObservableCollection<Relationship>();


        private int _Multiplicator;

        public int Multiplicator
        {
            get { return _Multiplicator == 0 ? 10 : _Multiplicator; }
            set { SetProperty(ref _Multiplicator, value); }
        }


        private BarCycle _OppotunityBarType = BarCycles.H1;

        public BarCycle OpportunityCycle
        {
            get { return _OppotunityBarType; }
            set { SetProperty(ref _OppotunityBarType, value); }
        }

        private Opportunity _Opportunity;
        public Opportunity Opportunity
        {
            get { return _Opportunity; }
            set { SetProperty(ref _Opportunity, value); }
        }


        #region 释放

        private ReleaseDirection? _ReleaseDirection;

        public ReleaseDirection? ReleaseDirection
        {
            get { return _ReleaseDirection; }
            set { SetProperty(ref _ReleaseDirection, value); }
        }


        private ReleaseLevel? _ReleaseLevel;

        public ReleaseLevel? ReleaseLevel
        {
            get { return _ReleaseLevel; }
            set { SetProperty(ref _ReleaseLevel, value); }
        }

        private double? _ReleaseScope;

        public double? ReleaseScope
        {
            get { return _ReleaseScope; }
            set { SetProperty(ref _ReleaseScope, value); }
        }

        private int? _ReleaseBarCount;

        public int? ReleaseBarCount
        {
            get { return _ReleaseBarCount; }
            set { SetProperty(ref _ReleaseBarCount, value); }
        }


        #endregion

        #region 积累
        private double? _CumulationScope;

        public double? CumulationScope
        {
            get { return _CumulationScope; }
            set { SetProperty(ref _CumulationScope, value); }
        }

        private int? _CumulationBarCount;

        public int? CumulationBarCount
        {
            get { return _CumulationBarCount; }
            set { SetProperty(ref _CumulationBarCount, value); }
        }

        private CumulationType _CumulationType;

        public CumulationType CumulationType
        {
            get { return _CumulationType; }
            set { SetProperty(ref _CumulationType, value); }
        }

        private int? _CumulationPoints;

        public int? CumulationPoints
        {
            get { return _CumulationPoints; }
            set { SetProperty(ref _CumulationPoints, value); }
        }

        private BarCycle[] _CumulationCycles;

        public BarCycle[] CumulationCycles
        {
            get { return _CumulationCycles; }
            set { SetProperty(ref _CumulationCycles, value); }
        }


        #endregion



        public double Completeness => CalcCompleteness();



        public OpenDealViewModel OpenDeal { get; } = new OpenDealViewModel();


        public PhotoInfo CoverPhoto { get; set; }

        public ObservableCollection<DealViewModel> DealRecords { get; } = new ObservableCollection<DealViewModel>();


        public ObservableCollection<PhotoInfo> PhotoInfos { get; } = new ObservableCollection<PhotoInfo>();

        /// <summary>
        /// 心得
        /// </summary>
        public ObservableCollection<string> Remarks { get; } = new ObservableCollection<string>();

        public ObservableCollection<string> Questions { get; } = new ObservableCollection<string>();

        /// <summary>
        /// 标签
        /// </summary>
        public ObservableCollection<string> Marks { get; } = new ObservableCollection<string>();

        public class ScoreVM : BindableBase
        {
            private int? _Full;

            public int? Full
            {
                get { return _Full; }
                set { SetProperty(ref _Full, value); }
            }

            private int? _Release;

            public int? Release
            {
                get { return _Release; }
                set { SetProperty(ref _Release, value); }
            }

            private int? _Cumulation;

            public int? Cumulation
            {
                get { return _Cumulation; }
                set { SetProperty(ref _Cumulation, value); }
            }

        }


        // public ScoreVM Scores { get; } = new ScoreVM();

        public ObservableCollection<ScoreItemViewModel> Scores { get; set; } = new ObservableCollection<ScoreItemViewModel>();


        private RoadMap _RoadMap;

        public RoadMap RoadMap
        {
            get { return _RoadMap; }
            set { SetProperty(ref _RoadMap, value); }
        }

        public string GroupId { get => record?.Id; set => record.GroupId = value; }

        private Dictionary<T, string> GenarateItems<T>() where T : Enum
        {
            var rr = new Dictionary<T, string>();
            foreach (System.Reflection.FieldInfo item in typeof(T).GetFields())
            {
                object[] des = item.GetCustomAttributes(typeof(DescriptionAttribute), false);

                if (des != null && des.FirstOrDefault() is DescriptionAttribute description)
                    rr.Add((T)item.GetValue(null), description.Description);
            }
            return rr;
        }


        public NewRecordWindowViewModel()
        {
            //record.Release = new ReleaseInfo();
            //record.Cumulation = new CumulationInfo();
            //record.OpenDeal = new OpenDeal();
            //record.CloseDeals = new List<CloseDeal>();
            //record.Questions = new List<string>();
            //record.Lessons = new List<string>();
            CumulationCycles = (ConfigurationManager.GetSection("BarTypes") as List<BarCycle>)?.ToArray();

            OpenDeal.RecordId = RecordId;
            OpenDeal.PhotoSource.Source = PhotoInfos;
            OpenDeal.PropertyChanged += (s, e) => { NotifyPropertyChanged(nameof(CanClose)); NotifyPropertyChanged(nameof(CanOpen)); };
            DealRecords.CollectionChanged += DealRecords_CollectionChanged;

            RoadMap = new RoadMap(record);
        }

        //public NewRecordWindowViewModel(RoadMap map):this()
        //{
        //    RoadMap = map;
        //}

        private static bool IsAvailable(OpenDealViewModel openDeal)
        {
            if (string.IsNullOrWhiteSpace(openDeal.DealId))
                return false;
            if (!openDeal.Lots.HasValue || openDeal.Lots.Value == 0)
                return false;
            if (!openDeal.Price.HasValue || openDeal.Price.Value == 0)
                return false;
            if (!openDeal.Time.HasValue || openDeal.Time.Value == default)
                return false;
            if (openDeal.Sequence < 0)
                return false;
            if (openDeal.TradeCycle == null)
                return false;
            return true;
        }

        private void DealRecords_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
        {
            if (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Add)
            {
                foreach (DealViewModel item in e.NewItems)
                {
                    item.RecordId = RecordId;
                    item.PhotoSource.Source = PhotoInfos;
                    item.TradeCycle = OpenDeal.TradeCycle;
                }
            }
        }

        protected override void OnPropertyChanged<T>(string propertyName, T oldValue, T newValue)
        {
            base.OnPropertyChanged(propertyName, oldValue, newValue);
            if (propertyName != nameof(Completeness))
                NotifyPropertyChanged(nameof(Completeness));
        }


        private double CalcCompleteness()
        {
            double d = 0;
            if (!string.IsNullOrWhiteSpace(Contract))
                d += 5;

            //总结10
            d += Math.Min(10, Remarks.Count * 2 + CalcScore());

            //机会40
            d += 5;//周期
            if (ReleaseDirection != null)
                d += 5;
            if (ReleaseLevel != null)
                d += 5;
            if (ReleaseScope != null)
                d += 5;
            if (ReleaseBarCount != null)
                d += 5;
            if (CumulationScope != null)
                d += 5;
            if (CumulationBarCount != null)
                d += 5;



            //入场30


            //离场20

            return d / 100;
        }
        #region score

        private double CalcScore()
        {
            return 0;
            double d = 0;
            var ps = Scores.GetType().GetProperties();
            foreach (var item in ps)
            {
                if (item.GetValue(Scores, null) != null)
                    ++d;
            }
            return d;
        }

        private double CalcObject(object o, double total)
        {
            double d = 0;
            var ps = o.GetType().GetProperties();
            var v = total / ps.Length;
            foreach (var item in ps)
            {
                if (item.GetValue(o, null) != null)
                    d += v;
            }
            return d;
        }

        #endregion






        public Record Build()
        {
            record.Contract = Contract;
            record.Multiplicator = Multiplicator;
            record.Id = RecordId;
            if (OpenDeal.Time.HasValue)
                record.Date = OpenDeal.Time.Value;

            record.Version = Assembly.GetCallingAssembly().GetName().Version;

            record.OpportunityCycle = OpportunityCycle;
            record.Lessons = Remarks.ToList();
            record.Questions = Questions.ToList();
            record.Marks = Marks.ToList();
            if (OpenDeal.Time.HasValue)
                record.Date = OpenDeal.Time.Value;
            record.SaveTime = DateTime.Now; 

            record.OpenDeal = new OpenDeal
            {
                Id = OpenDeal.DealId,
                Lots = OpenDeal.Lots.HasValue ? OpenDeal.Lots.Value : default,
                OpenDirection = OpenDeal.OpenDirection,
                Price = OpenDeal.Price.HasValue ? OpenDeal.Price.Value : default,
                //Reasons = OpenDeal.Reasons.ToList(),
                RecordId = RecordId,
                Sequence = 0,
                Time = OpenDeal.Time.HasValue ? OpenDeal.Time.Value : default,
                TradeCycle = OpenDeal.TradeCycle,
                Photos = PhotoInfos.Where(x => x.DealId == OpenDeal.DealId).ToList(),
                TradeType = TradeType.Open
            };
            record.OpenDeal.Reasons.AddRange(OpenDeal.Reasons);

            double unclosed = OpenDeal.Lots.HasValue ? OpenDeal.Lots.Value : 0;
            //if (record.CloseDeals == null)
                record.CloseDeals = new List<CloseDeal>();
            for (int i = 0; i < DealRecords.Count; i++)
            {
                var item = DealRecords[i];
                record.CloseDeals.Add(new CloseDeal
                {
                    Id = item.DealId,
                    Lots = item.Lots.HasValue ? item.Lots.Value : default,
                    Price = item.Price.HasValue ? item.Price.Value : default,
                    Reasons = item.Reasons.ToList(),
                    RecordId = RecordId,
                    Sequence = ++i,
                    Time = item.Time.HasValue ? item.Time.Value : default,
                    TradeCycle = item.TradeCycle,
                    Highest = (item as UnderweightDealViewModel)?.Highest??0,
                    Lowest = (item as UnderweightDealViewModel)?.Lowest ?? 0,
                    Photos = PhotoInfos.Where(x => x.DealId == item.DealId).ToList(),
                    TradeType = item.Lots.HasValue && item.Lots.Value == unclosed ? TradeType.Close : TradeType.Underweight
                });
                unclosed -= (double)item.Lots;
            }

            record.Release = new ReleaseInfo
            {
                Id = Guid.NewGuid().ToString("N"),
                Direction = ReleaseDirection.HasValue ? ReleaseDirection.Value : default,
                Level = ReleaseLevel.HasValue ? ReleaseLevel.Value : default,
                Scope = ReleaseScope.HasValue ? ReleaseScope.Value : default,
                BarCount = ReleaseBarCount.HasValue ? ReleaseBarCount.Value : default,
                //Score = Scores.FirstOrDefault(x => x.Name == "")?.Value ?? 0
            };

            record.Cumulation = new CumulationInfo
            {
                Id = Guid.NewGuid().ToString("N"),
                Type = CumulationType,
                BarCount = CumulationBarCount.HasValue ? CumulationBarCount.Value : default,
                Points = CumulationPoints.HasValue ? CumulationPoints.Value : default,
                Scope = CumulationScope.HasValue ? CumulationScope.Value : default,
                //Score = Scores.Cumulation.HasValue ? Scores.Cumulation.Value : default
            };

            if (record.CoverPhoto == null)
                record.CoverPhoto = PhotoInfos.FirstOrDefault()?.Thumbnail;

            return record;
        }

    }
}
